package gui;

import application.Carte;
import application.CouleurTank;
import application.FrequenceFormes;
import application.PowerUp;
import application.Resolution;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.Area;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JPanel;

/**
 *
 * @author Usager
 */
public class Monde extends JPanel {

    private Jeu jeu;
    private Resolution resolution;
    private Carte carte;
    private ArrayList<Tank> tanks;
    public ArrayList<Projectile> projectiles;
    private ArrayList<Obstacle> obstacles;
    volatile private ArrayList<ElementDuJeu> aEnlever = new ArrayList<ElementDuJeu>();    
    private int locationMondeX, shakeTemps, nombreJoueurs, tour;

    public Monde(Jeu jeu, Resolution resolution) {
        this.jeu = jeu;
        this.resolution = resolution;

        setLayout(null);

        this.setBackground(Color.DARK_GRAY);

        initialisation();
        setListeners();

        setSize(jeu.getWidth() - locationMondeX, jeu.getHeight());
        setLocation(locationMondeX, 0);
    }
   
    
    
    public ArrayList<Tank> getTanks() {
        return tanks;
    }

    public int getTour() {
        return tour;
    }

    private void initialisation() {
        setCurseur();

        if (resolution == Resolution.R1920x1080) {
            locationMondeX = 300;
        } else if (resolution == Resolution.R1280x1024) {
            locationMondeX = 200;
        } else if (resolution == Resolution.R800x600) {
            locationMondeX = 125;
        }

        tanks = new ArrayList<>();
        projectiles = new ArrayList<>();
        obstacles = new ArrayList<>();        
        tour = 0;

        shakeTemps = 0;

    }

    public void changementDeTour() {
        int tankVivants=0;
        for (int i = 0; i < tanks.size(); i++)
        {
            if(tanks.get(i).vivant) {
            tankVivants++;
            }
        }
        if(tankVivants==1) {
            this.victoire();
        } else {
            tankVivants=0;
        }
        
        do {
            tanks.get(tour).resetTour();
            tour++;
            tour = tour % (nombreJoueurs);
        } while (!tanks.get(tour).vivant);
        
        jeu.setNomJoueurActif(tour);
    }

    /**
     * Configure le curseur pour le rendre invisible
     */
    private void setCurseur() {
        Cursor curseur;
        Image imageCurseur = Toolkit.getDefaultToolkit().getImage(ClassLoader.getSystemResource("images/Curseur.png"));
        Point pointCurseur = new Point(11, 0);
        curseur = Toolkit.getDefaultToolkit().createCustomCursor(imageCurseur, pointCurseur, "Curseur");

        setCursor(curseur);
    }

    private void setListeners() {

        this.addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {
                tanks.get(tour).bougerCibleCanon(e);
            }

            @Override
            public void mouseDragged(MouseEvent e) {
                tanks.get(tour).bougerCibleCanon(e);
            }
        });

        this.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                if (e.isMetaDown()) {
                    tanks.get(tour).bouger(e);
                } else {

                    try {
                        if (projectiles.isEmpty() && tanks.get(tour).projectilesRestants != 0) {
                            newProjectile(e);
                            tanks.get(tour).projectilesRestants--;
                            shakeTemps = 20;
                        }
                    } catch (Exception asd) {
                    }
                }
            }
        });

    }

    public void commencerLaPartie(int vieTanks, int fuelTanks, int ammoTanks, FrequenceFormes frequenceFormes) {
        jeu.setNomJoueurActif(0);
        genererTanks(vieTanks, fuelTanks, ammoTanks);
        genererObstacles(frequenceFormes.getFrequence());
        setListeners();
    }

    public void refresh(Resolution resolutionInitiale, Resolution resolutionActuelle) {
        double ratioX, ratioY;

        ratioX = (double) resolutionActuelle.getLargeur() / (double) resolutionInitiale.getLargeur();
        ratioY = (double) resolutionActuelle.getHauteur() / (double) resolutionInitiale.getHauteur();
        for (int i = 0; i < tanks.size(); i++) {
//            tanks.get(i).setSize(getWidth() / 5, getHeight() / 5);
//            tanks.get(i).setLocation((int) ((double) tanks.get(i).getX() * ratioX), (int) ((double) tanks.get(i).getY() * ratioY));
        }
        repaint();
    }

    void newProjectile(MouseEvent e) {
        projectiles.add(new Projectile(tanks.get(tour), this, e));
        add(projectiles.get(0));
    }

    public void mAJMonde() {
        detruireDesChosesBangbang();
        for (int i = 0; i < tanks.size(); i++) {
            if (!tanks.get(i).reverse) {
                tanks.get(i).progressionDeMouvement();
            } else {
                tanks.get(i).reverse();
            }
        }

        try {
            if (!(projectiles.isEmpty())) {
                projectiles.get(0).bougerProjectile();
            }
            if (!projectiles.get(0).checkValidity()) {
                this.remove(projectiles.get(0));
                projectiles.remove(0);
            }
        } catch (IndexOutOfBoundsException e) {
        }
        shake();
        if (tanks.size() > 0) {
            checkCollisions();
        }

    }

    public int getNombreJoueurs() {
        return nombreJoueurs;
    }

    public void setNombreJoueurs(int nombre) {
        nombreJoueurs = nombre;
    }

    public void genererTanks(int vieTanks, int fuelTanks, int ammoTanks) {

        switch (nombreJoueurs) {
            case 2: {
                tanks.add(new Tank(0, 0, (CouleurTank) jeu.getCmbCouleurTank1().getSelectedItem(), this));
                tanks.add(new Tank(this.getWidth() - 150, this.getHeight() - 150, (CouleurTank) jeu.getCmbCouleurTank2().getSelectedItem(), this));
            }
            break;
            case 3: {
                tanks.add(new Tank(0, 0, (CouleurTank) jeu.getCmbCouleurTank1().getSelectedItem(), this));
                tanks.add(new Tank(this.getWidth() - 150, this.getHeight() - 150, (CouleurTank) jeu.getCmbCouleurTank2().getSelectedItem(), this));
                tanks.add(new Tank(0, this.getHeight() - 150, (CouleurTank) jeu.getCmbCouleurTank3().getSelectedItem(), this));
            }
            break;
            case 4: {
                tanks.add(new Tank(0, 0, (CouleurTank) jeu.getCmbCouleurTank1().getSelectedItem(), this));
                tanks.add(new Tank(0, this.getHeight() - 150, (CouleurTank) jeu.getCmbCouleurTank2().getSelectedItem(), this));
                tanks.add(new Tank(this.getWidth() - 150, 0, (CouleurTank) jeu.getCmbCouleurTank3().getSelectedItem(), this));
                tanks.add(new Tank(this.getWidth() - 150, this.getHeight() - 150, (CouleurTank) jeu.getCmbCouleurTank4().getSelectedItem(), this));
            }
            break;
        }

        for (int i = 0; i < tanks.size(); i++) {
            this.add(tanks.get(i));
        }


        for (int i = 0; i < tanks.size(); i++) {

            tanks.get(i).maxHP = vieTanks;
            tanks.get(i).hP = vieTanks;
            tanks.get(i).fuelMax = fuelTanks;
            tanks.get(i).fuel = fuelTanks;
            tanks.get(i).nombreProjectiles = ammoTanks;
            tanks.get(i).projectilesRestants = ammoTanks;
        }
        switch (nombreJoueurs) {
            case 2: {
                this.setPowerUP(1, (PowerUp) jeu.getCmbPowerUp1().getSelectedItem());
                this.setPowerUP(2, (PowerUp) jeu.getCmbPowerUp2().getSelectedItem());

            }
            break;
            case 3: {
                this.setPowerUP(1, (PowerUp) jeu.getCmbPowerUp1().getSelectedItem());
                this.setPowerUP(2, (PowerUp) jeu.getCmbPowerUp2().getSelectedItem());
                this.setPowerUP(3, (PowerUp) jeu.getCmbPowerUp3().getSelectedItem());
            }
            break;
            case 4: {
                this.setPowerUP(1, (PowerUp) jeu.getCmbPowerUp1().getSelectedItem());
                this.setPowerUP(2, (PowerUp) jeu.getCmbPowerUp2().getSelectedItem());
                this.setPowerUP(3, (PowerUp) jeu.getCmbPowerUp3().getSelectedItem());
                this.setPowerUP(4, (PowerUp) jeu.getCmbPowerUp4().getSelectedItem());
            }

        }
    }

    void shake() {
        if (shakeTemps != 0) {
            if (shakeTemps > 15) {
                if (shakeTemps % 2 == 0) {
                    this.setLocation(locationMondeX + 10, 10);
                } else if (shakeTemps % 2 == 1) {
                    this.setLocation(locationMondeX - 10, -10);
                }
            } else if (shakeTemps > 10) {
                if (shakeTemps % 2 == 0) {
                    this.setLocation(locationMondeX + 7, 7);
                } else if (shakeTemps % 2 == 1) {
                    this.setLocation(locationMondeX - 7, -7);
                }
            } else if (shakeTemps > 5) {
                if (shakeTemps % 2 == 0) {
                    this.setLocation(locationMondeX + 5, 5);
                } else if (shakeTemps % 2 == 1) {
                    this.setLocation(locationMondeX - 5, -5);
                }
            } else if (shakeTemps >= 0) {
                if (shakeTemps % 2 == 0) {
                    this.setLocation(locationMondeX + 3, 3);
                } else if (shakeTemps % 2 == 1) {
                    this.setLocation(locationMondeX - 3, -3);
                }
            }
            shakeTemps -= 1;
        } else {
            this.setLocation(locationMondeX, 0);
        }
    }

    public void setLocationMondeX(int locationX) {
        locationMondeX = locationX;
    }

    public int getLocationMondeX() {
        return locationMondeX;
    }

    public Carte getCarte() {
        return carte;
    }

    public void setCarte(Carte newCarte) {
        carte = newCarte;
    }

    private void detruireDesChosesBangbang() {
        for (int i = 0; i < aEnlever.size(); i++) {
            this.remove(aEnlever.get(i));
        }
        //tanks.removeAll(aEnlever);
        projectiles.removeAll(aEnlever);
        aEnlever = new ArrayList<>();

    }

    public void setPowerUP(int tank, PowerUp pU) {
        tanks.get(tank - 1).setPowerUP(pU);
    }

    private void checkCollisions() {
        try {
            //Autres tanks

            for (int j = 0; j < tanks.size(); j++) {
                Area intersection = (Area) tanks.get(tour).getAireObstacle().clone();
                intersection.intersect(tanks.get(j).getAire());
                if (!intersection.isEmpty() && j != tour && !tanks.get(tour).reverse && tanks.get(j).vivant) {
                    if (tanks.get(tour).peutRam) {
                        tanks.get(j).reduceHP(tanks.get(tour).ramPower);
                        tanks.get(tour).peutRam = false;
                        Explosion explosion = new Explosion(this, intersection.getBounds().x, intersection.getBounds().y, 70, 1);
                        add(explosion);
                        setComponentZOrder(explosion, 0);
                    }
                    tanks.get(tour).reduceHP(1);
                    if (tanks.get(tour).reverse) {
                        tanks.get(tour).reverse = false;
                    } else {
                        tanks.get(tour).reverseStart();
                    }
                }
                if (tanks.get(j).getHP() <= 0) {
                    tanks.get(j).setVivant(false);
                }
            }
            //obstacles            

            for (int i = 0; i < obstacles.size(); i++) {
                Area intersectionObj = (Area) tanks.get(tour).getAireObstacle().clone();
                intersectionObj.intersect(obstacles.get(i).getArea());
                if (!intersectionObj.isEmpty() && !tanks.get(tour).reverse) {
                    tanks.get(tour).reduceHP(tanks.get(tour).ramPower - 1);
                    tanks.get(tour).reverseStart();
                }
                if (tanks.get(tour).getHP() <= 0) {
                    tanks.get(tour).setVivant(false);
                }
            }
            //projectiles
            for (int i = 0; i < tanks.size(); i++) {
                if (tanks.get(i).vivant && tanks.get(i).getAire().contains(projectiles.get(0).pointProjectile)) {
                    Explosion explosion = new Explosion(this, projectiles.get(0).getX(), projectiles.get(0).getY(), 70, 1);
                    add(explosion);
                    setComponentZOrder(explosion, 0);

                    aEnlever.add(projectiles.get(0));
                    tanks.get(i).reduceHP(tanks.get(tour).dmg);
                    this.shakeTemps = 20;

                    if (tanks.get(i).getHP() <= 0) {
                        tanks.get(i).setVivant(false);
                    }
                }
                for (int j = 0; j < obstacles.size(); j++) {
                    if (obstacles.get(j).getArea().contains(projectiles.get(0).pointProjectile)) {
                        Explosion explosion = new Explosion(this, projectiles.get(0).getX(), projectiles.get(0).getY(), 70, 1);
                        add(explosion);
                        setComponentZOrder(explosion, 0);

                        aEnlever.add(projectiles.get(0));
                        this.shakeTemps = 20;
                    }
                }
            }
        } catch (IndexOutOfBoundsException e) {
        }
    }

    public Resolution getResolution() {
        return resolution;
    }

    private void genererObstacles(int nombre) {
        switch (resolution) {
            case R1920x1080: {
                Obstacle centre = new Obstacle(this, this.getWidth() / 2 - this.getWidth() / 6, getHeight() / 2 - this.getHeight() / 6, this.getWidth() / 3, getHeight() / 3, 1);
                obstacles.add(centre);
                this.add(centre);

            }
            break;
            case R1280x1024: {
                Obstacle RCGH = new Obstacle(this, this.getWidth() / 9, getHeight() / 8, this.getWidth() / 4, getHeight() / 12, 0);
                obstacles.add(RCGH);
                this.add(RCGH);
                Obstacle RCGB = new Obstacle(this, this.getWidth() / 9, getHeight() - getHeight() / 5, this.getWidth() / 4, getHeight() / 12, 0);
                obstacles.add(RCGB);
                this.add(RCGB);
                Obstacle RCDH = new Obstacle(this, this.getWidth() - this.getWidth() / 9 - this.getWidth() / 4, getHeight() / 8, this.getWidth() / 4, getHeight() / 12, 0);
                obstacles.add(RCDH);
                this.add(RCDH);
                Obstacle RCDB = new Obstacle(this, this.getWidth() - this.getWidth() / 9 - this.getWidth() / 4, getHeight() - getHeight() / 5, this.getWidth() / 4, getHeight() / 12, 0);
                obstacles.add(RCDB);
                this.add(RCDB);

                Obstacle RLGH = new Obstacle(this, this.getWidth() / 9, getHeight() / 8, getHeight() / 12, this.getWidth() / 4, 0);
                obstacles.add(RLGH);
                this.add(RLGH);
                Obstacle RLDH = new Obstacle(this, this.getWidth() - this.getWidth() / 9 - getHeight() / 12, getHeight() / 8, getHeight() / 12, this.getWidth() / 4, 0);
                obstacles.add(RLDH);
                this.add(RLDH);
                Obstacle RLGB = new Obstacle(this, this.getWidth() / 9, getHeight() - (int) 2 * (getHeight() / 5), getHeight() / 12, this.getWidth() / 4, 0);
                obstacles.add(RLGB);
                this.add(RLGB);
                Obstacle RLDB = new Obstacle(this, this.getWidth() - this.getWidth() / 9 - getHeight() / 12, getHeight() - (int) 2 * (getHeight() / 5), getHeight() / 12, this.getWidth() / 4, 0);
                obstacles.add(RLDB);
                this.add(RLDB);

                Obstacle RMG = new Obstacle(this, 0, getHeight() / 2 - getHeight() / 36, this.getWidth() / 8, getHeight() / 18, 0);
                obstacles.add(RMG);
                this.add(RMG);
                Obstacle RMD = new Obstacle(this, this.getWidth() - this.getWidth() / 8, getHeight() / 2 - getHeight() / 36, this.getWidth() / 8, getHeight() / 18, 0);
                obstacles.add(RMD);
                this.add(RMD);
                Obstacle RHM = new Obstacle(this, this.getWidth() / 2 - getHeight() / 36, 0, getHeight() / 18, this.getWidth() / 8, 0);
                obstacles.add(RHM);
                this.add(RHM);
                Obstacle RBM = new Obstacle(this, this.getWidth() / 2 - getHeight() / 36, getHeight() - this.getWidth() / 8, getHeight() / 18, this.getWidth() / 8, 0);
                obstacles.add(RBM);
                this.add(RBM);

                Obstacle centre = new Obstacle(this, this.getWidth() / 2 - this.getWidth() / 6, getHeight() / 2 - this.getHeight() / 6, this.getWidth() / 3, getHeight() / 3, 1);
                obstacles.add(centre);
                this.add(centre);

            }
            break;
            case R800x600: {
                Obstacle RMG = new Obstacle(this, 0, getHeight() / 2 - getHeight() / 36, this.getWidth() / 6, getHeight() / 18, 0);
                obstacles.add(RMG);
                this.add(RMG);
                Obstacle RMD = new Obstacle(this, this.getWidth() - this.getWidth() / 6, getHeight() / 2 - getHeight() / 36, this.getWidth() / 6, getHeight() / 18, 0);
                obstacles.add(RMD);
                this.add(RMD);
                Obstacle RHM = new Obstacle(this, this.getWidth() / 2 - getHeight() / 36, 0, getHeight() / 18, this.getWidth() / 6, 0);
                obstacles.add(RHM);
                this.add(RHM);
                Obstacle RBM = new Obstacle(this, this.getWidth() / 2 - getHeight() / 36, getHeight() - this.getWidth() / 6, getHeight() / 18, this.getWidth() / 6, 0);
                obstacles.add(RBM);
                this.add(RBM);

                Obstacle centre = new Obstacle(this, this.getWidth() / 2 - this.getWidth() / 6, getHeight() / 2 - this.getHeight() / 6, this.getWidth() / 3, getHeight() / 3, 1);
                obstacles.add(centre);
                this.add(centre);

            }
            break;

        }





//        boolean obstaclePlace = false;
//        for (int i = 0; i < nombre; i++) {
//            while (!obstaclePlace) {
//                Obstacle obstacle = new Obstacle(this);
//                Area intersection = (Area) obstacle.getArea().clone();
//
//                for (int j = 0; j < tanks.size(); j++) {
//
//                    System.out.println(obstacle.getArea().getBounds());
//                    intersection.intersect(tanks.get(j).getAire());
//                    if (!obstacle.getArea().getBounds().intersects(tanks.get(j).getAire().getBounds())) {
//                        obstacles.add(obstacle);
//                        this.add(obstacle);
//
//                        obstaclePlace = true;
//                    } else {
//                        intersection = (Area) obstacle.getArea().clone();
//                    }
//                }
//            }
//            obstaclePlace = false;
//        }
    }
    public void victoire() {
        
    }
}
